class Compiler {
  constructor(vm) {
    this.vm = vm

    this.compile(this.vm.$el)
    console.log(222)
  }

  compile(el) {
    const childNodes = Array.from(el.childNodes)
    if (childNodes.length) {
      childNodes.forEach(node => {
        if (this.isTextNode(node)) {
          this.compileText(node)
        } else if (this.isElementNode(node)) {
          this.compileElement(node)
        }

        if (node.childNodes && node.childNodes.length) {
          this.compile(node)
        }
      })
    }
  }

  compileText(node) {
    const text = node.textContent
    const reg = /\{\{(.+?)\}\}/
    if (reg.test(text)) {
      node.textContent = text.replace(reg, this.vm[RegExp.$1.trim()])

      new Watcher(this.vm, RegExp.$1.trim(), newValue => {
        node.textContent = text.replace(reg, newValue)
      })
    }
  }

  compileElement(node) {
    const _this = this
    const attrs = Array.from(node.attributes)

    attrs.forEach(attr => {
      const name = attr.name
      const key = attr.value
      if (this.isDirective(name)) {
        let _tempName = name
        let eventName = null

        if (name.includes('v-on')) {
          _tempName = name.split(':')[0]
          eventName = name.split(':')[1]
        }

        const directiveName = this.getDirectiveName(_tempName)
        console.log(directiveName)
        this[`${directiveName}Updater`] && this[`${directiveName}Updater`].call(_this, node, this.vm.$data[key], key, eventName)
      }
    })
  }

  textUpdater(node, value, key) {
    node.textContent = value

    new Watcher(this.vm, key, newValue => {
      node.textContent = newValue
    })
  }

  modelUpdater(node, value, key) {
    node.value = value

    node.addEventListener('input', () => {
      this.vm.$data[key] = node.value
    })

    new Watcher(this.vm, key, newValue => {
      node.value = newValue
    })
  }

  htmlUpdater(node, value, key) {
    node.innerHTML = value

    new Watcher(this.vm, key, newValue => {
      node.innerHTML = newValue
    })
  }

  onUpdater(node, value, key, event) {
    node.addEventListener(event, this.vm[key].bind(this.vm))
  }

  getDirectiveName(name) {
    return name.substr(2)
  }

  isDirective(attr) {
    return attr.startsWith('v-')
  }

  isTextNode(node) {
    return node.nodeType === 3
  }

  isElementNode(node) {
    return node.nodeType === 1
  }
}